// 遍历数据,执行回调


/*
** 遍历由对象和数组为结构的数据, 直到遍历到非对象或非数组，同时通过path缓存遍历路径, 执行回调
** 方法主要用于数据结构的转换
*/

function isObject (obj){
	return Object.prototype.toString.call(obj) === '[object Object]';
}

function isArray (arr){
    return Object.prototype.toString.call(arr) === '[object Array]';
}



/*
** 遍历对象
** @describe
        便利对象到根属性,并记录遍历路径
** @params
        beLoop: 被遍历对象
        fn: 末尾处理函数
        path: 便利路径记录
*/
function loopData (beLoop, fn, path=""){

    let loop = {};
    let isObj = true;

    if(isObject(beLoop)){
        
        loop = Object.keys(beLoop)
    
    }else if(isArray(beLoop)){

        loop = beLoop;
        isObj = false;
    
    }else{

        console.log('循环对象类型错误', beLoop)
        return beLoop;
    }

    loop.forEach((item, index) =>{

        let delimiter = path ? '-' : '';
        
        let history = isObj ? item : index;
        let data = isObj ? beLoop[item] : item;
        let pathHistory = path + delimiter + history;
            
        if(isObject(data) || isArray(data)){
            loopData(data, fn, pathHistory)
        }else{
            fn(beLoop, item, pathHistory, data);
        }

    })
}



// 重构
function restructure(data){
    let cache = {};

    loopData(data, (beLoop, item, pathHistory, data) =>{
        cache[pathHistory] = data;
    })
    return cache
} 



/*
** 生成映射表
** @describe
        通过遍历两个对象，当找到对应标识后，生成路径映射
** @params
        source: 取值对象
        target: 赋值对象
*/
function creatMap(source, target){
    let map = {};
    let data = {source, target};
    let path = {
        source: {},
        target: {}
    };
    let has = false;
    
    // 生成地址
    Object.keys(path).forEach((key) =>{
        path[key] = restructure(data[key])
    })

    // 寻找标记点
    Object.keys(path.source).forEach((srouceKey) =>{
        let sourceIden = path.source[srouceKey];

        Object.keys(path.target).forEach((targetKey) =>{
            let targetIden = path.target[targetKey];

            if(sourceIden === targetIden && targetIden !== ''){
                has = true;
                map[srouceKey] = targetKey;
            }
        })
    })
    
    if(!has){console.log('未找到匹配设置')}

    return map
}



/*
** 寻址, getValue 是否为取值
** @params
        data: 取值对象
        pathStr: 取值路径
        getValue: 是否将末尾值添加到路径
        callback: 末尾回调
*/
function addressing (data, pathStr, getValue, callback){
    let pathArr = pathStr.split('-');
    let lastPath = getValue !== undefined ? pathArr.pop() : '';
    let cache;

    
    pathArr.forEach((value, index) =>{

        if(value === pathArr[pathArr.length-1] && callback){
            cache[value] = callback(cache[value])
        }
                
        if(!index){
            // 初始值
            cache = data[value];
        }else{
            cache = cache ? cache[value] : "";
        }

    })

    if(getValue !== undefined){
       
        cache = cache === undefined ? data : cache;
        cache[lastPath] = getValue; 
    }

    return cache;
    
}



/*
** 反向构成对象
** @params
        map: 映射路径
        reverse: boolean 是否构建目标对象
*/
function reverseBuild (map, reverse){

    let cache = []
    let target = {}
    
    Object.keys(map).forEach(path =>{

       path = reverse ? map[path] : path;
    
       cache.push(path.split('-'))
    })

    cache.forEach(item =>{
        creat(item, target, 0);
    })

    function creat(arr, target, num){

        if(num < arr.length){

            let key = arr[num];

            if(target.hasOwnProperty(key)){
                creat( arr, target[key], num+1 )
            }else{

                let cunt = parseInt(key);
                let b = isNaN(cunt) ? key : cunt;


                if(num+1 <arr.length){
                    target[b] = !isNaN(parseInt(arr[num+1])) ? [] : {};
                    creat(arr, target[b], num+1)
                }else{
                    target[b] = ""
                }
               
            }
            
        }
        
    }

    return target
}



/*
** 映射方向
** @params
        map: 映射反向
*/
function reverseMap(map){
    let cache = {};

    Object.keys(map).forEach(key =>{
        cache[map[key]] = key;
    })

    return cache;
}



/*
** 赋值
** @params
        data: 取值对象
        template: 赋值对象
        map: 映射关系
        backVal: 是否返回值
        callBack: 指处理函数
*/
function assignment (data, template, map, backVal=false, callBack){
    
    Object.keys(map).forEach((sourcePath) =>{
        
        let targetPath = map[sourcePath];
        let value = addressing(data, sourcePath);

        if(callBack){
            value = callBack(value)
        }
        
        addressing(template, targetPath, value); 
    })
    
    if(backVal){
        return template;
    }
    
}


export default  {

    addressing,
    restructure,
    creatMap,
    assignment,
    loopData,
    reverseBuild,
    reverseMap,

}